var _vec3f = require('core/glm.js').vec3f;
var _Helper = require('third_party/tweenjs/helper.js');

var MOVE_LEFT = 0;
var MOVE_TOP = 1;
var MOVE_RIGHT = 2;
var MOVE_BOTTOM = 3;

var _Constant = require('scenes/game/constant.js');
var UNIT_WIDTH = _Constant.slotSize[0];
var UNIT_HEIGHT = _Constant.slotSize[1];

var TWEEN = require('./tweens.js');

// ==========================
// AbsorbParam
// ==========================
/**
 * @param vector vector[0] or vector[1]
 * @param direction
 * @param cancel min movement
 * @param absorb
 * @param distance
 * @constructor
 */
function AbsorbParam(vector, direction, cancel, absorb, distance) {
    this.vector = vector;
    this.direction = direction;
    this.cancel = cancel;
    this.absorb = absorb;
    this.distance = distance;
}
AbsorbParam.prototype.setDistance = function (dis) {
    this.distance = dis;
};

// ==========================
// Animations
// ==========================
function Animations(gamearea) {
    this.mGamearea = gamearea;

    this.mParams = new Array(4);
    this.mParams[MOVE_LEFT] = new AbsorbParam(0, new _vec3f(-1, 0, 0), 15, UNIT_WIDTH, 300);
    this.mParams[MOVE_RIGHT] = new AbsorbParam(0, new _vec3f(1, 0, 0), 15, UNIT_WIDTH, 300);
    this.mParams[MOVE_TOP] = new AbsorbParam(1, new _vec3f(0, 1, 0), 15, UNIT_HEIGHT, 300);
    this.mParams[MOVE_BOTTOM] = new AbsorbParam(1, new _vec3f(0, -1, 0), 15, UNIT_HEIGHT, 300);

    this.mDirection = MOVE_LEFT;
    this.mAbsorbVec = _Helper.createPoint();// used for absorb
    this.mNextVec = _Helper.createPoint();// used for slidein
    this.mNextSlot = null;

    this.mAbsorbed = false;// if absorb to new position
    this.mSlideIn = false;

    // animation properties
    this.absorb = 0;
    this.distance = 0;// cell add animation

    // animations
    this.mAbsorbTarget = {absorb: 0};
    this.mAbsorb = new TWEEN.Tween(this)
        .to(this.mAbsorbTarget, 0.2)
        .onUpdate(this.onAbsorb)
        .onComplete(this.onAbsorbFinish);
    this.mSlideTarget = {distance: 0};
    this.mNext = new TWEEN.Tween(this)
        .to(this.mSlideTarget, 0.3)
        .easing(TWEEN.Easing.Quadratic.Out)
        .onStart(this.onNextStart)
        .onUpdate(this.onNext)
        .onComplete(this.onNextFinish);
}

// ---------------- animation callbacks
Animations.prototype.onAbsorb = function () {
    this.mGamearea.onAbsorb(this.mDirection, this.mAbsorbVec.getPosition(this.absorb));
};
Animations.prototype.onAbsorbFinish = function () {
    if (this.mAbsorbed) {
        this.mGamearea.onAbsorbFinished(this.mSlideIn);
    } else {
        this.mGamearea.onAbsorbCancel();
    }
};
Animations.prototype.onNextStart = function () {
    this.mGamearea.onSlideinStart(this.mNextSlot);
};
Animations.prototype.onNext = function () {
    this.mNextSlot.slideIn(this.mDirection, this.mNextVec.getPosition(this.distance));
};
Animations.prototype.onNextFinish = function () {
    this.mNextSlot = null;
    this.mGamearea.onSlideinFinish();
};
Animations.prototype.update = function (stride) {
    TWEEN.update(stride);
};

/**
 * @param direction
 * @param offset
 * @returns {boolean} generate next cell or not
 */
Animations.prototype.initMove = function (direction, offset) {
    this.mDirection = direction;
    this.mSlideIn = false;
    this.mAbsorbed = false;

    var param = this.mParams[direction];
    this.mAbsorbVec.setDirection(param.direction);
    this.absorb = Math.abs(offset[param.vector]);

    if (this.absorb <= param.cancel) {
        this.mAbsorbTarget.absorb = 0;
        this.mAbsorb.chain();
    } else {
        this.mNextVec.setDirection(param.direction);
        this.distance = -param.distance;
        this.mNext.to(this.mSlideTarget, param.distance / 1200);

        this.mAbsorbTarget.absorb = param.absorb;
        this.mAbsorb.chain(this.mNext);

        this.mAbsorbed = true;
        this.mSlideIn = true;
    }

    return this.mAbsorbed;
};
Animations.prototype.start = function (slot) {
    this.mNextSlot = slot;
    this.mAbsorb.start();
};
Animations.prototype.isAbsorbAccepted = function () {
    return this.mAbsorbed;
};

// ---------------- method for toturial
/**
 * @param direction
 * @param offset
 * @returns {boolean} will merge or not
 */
Animations.prototype.startAbsorbOnly = function (direction, offset) {
    this.mDirection = direction;
    this.mSlideIn = false;
    this.mAbsorbed = false;

    var param = this.mParams[direction];
    this.mAbsorbVec.setDirection(param.direction);
    this.absorb = Math.abs(offset[param.vector]);

    this.mAbsorb.chain();

    if (this.absorb <= param.cancel) {
        this.mAbsorbTarget.absorb = 0;
    } else {
        this.mAbsorbTarget.absorb = param.absorb;
        this.mAbsorbed = true;
    }

    return this.mAbsorbed;
};
Animations.prototype.setMargin = function (left, top, right, bottom) {
    this.mParams[MOVE_LEFT].setDistance(left + _Constant.slotSize[0]);
    this.mParams[MOVE_RIGHT].setDistance(right + _Constant.slotSize[0]);
    this.mParams[MOVE_TOP].setDistance(top + _Constant.slotSize[1]);
    this.mParams[MOVE_BOTTOM].setDistance(bottom + _Constant.slotSize[1]);
};

module.exports = Animations;
